#include <iostream>
#include <vector>
#include <memory>
#include <cmath>

using namespace std;
using TensorType = vector<float>;

class Variable{
public:
    Variable(const shared_ptr<TensorType>& data) {
        this->data = data;
    }

    shared_ptr<TensorType> data;
};

class Function {
public:
    Variable operator()(const Variable& input) {
        auto x = input.data;
        auto y = this->forward(x);

        return Variable(y);
    }
protected:
    virtual shared_ptr<TensorType> forward(const shared_ptr<TensorType>& in) = 0;

};

class Square : public Function {
protected:
    shared_ptr<TensorType> forward(const shared_ptr<TensorType>& in) override {
        auto out = make_shared<TensorType>();
        for (auto e: *in) {
            out->push_back(e * e);
        }

        return out;
    }
};

class Exp : public Function {
protected:
    shared_ptr<TensorType> forward(const shared_ptr<TensorType>& in) override {
        auto out = make_shared<TensorType>();
        for (auto e: *in) {
            out->push_back(exp(e));
        }

        return out;
    }
};

int main() {
    Square A;
    Exp B;
    Square C;

    auto data = make_shared<TensorType>(TensorType{0.5});
    Variable x(data);

    auto a = A(x);
    auto b = B(a);
    auto c = C(b);

    cout << (*c.data)[0] << endl;

    return 0;
}